#include<iostream>
#include<queue>
#include<pthread.h>
using namespace std;


const int default_cap = 5;
template<class T>
class ThreadPool
{
private:
  //构造函数私有化 + 拷贝构造/赋值重载函数禁用掉
  ThreadPool(int cap = default_cap) :_cap(cap) 
  {
    pthread_mutex_init(&_mtx,nullptr);
    pthread_cond_init(&_cond,nullptr);
  }
  ThreadPool(const ThreadPool<T>&) = delete;
  ThreadPool<T>& operator=(const ThreadPool<T>&) = delete;
public:
  //提供一个函数获取该全局唯一的对象
  static ThreadPool<T>* GetInstance()
  {
    static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; //这个锁和_mtx不同,这个锁是为了保证创建对象和if判断的原子性,由于是静态初始化,所以不需要销毁
    if(ins == nullptr)
    {
      pthread_mutex_lock(&lock);
      if(ins == nullptr)
      {
        ins = new ThreadPool<T>();
        cout <<"首次加载对象 :" << ins << endl;
        ins->InitThreadPool(); //注意:在这里要初始化线程池 / 在外部通过这个全局的对象调用InitThreadPool函数
        cout <<"线程池初始化success !" << endl;
      }
      pthread_mutex_unlock(&lock);
    }
    return ins;
  }
  ~ThreadPool()
  {
    pthread_mutex_destroy(&_mtx);
    pthread_cond_destroy(&_cond);
  }
  static void* Routine(void* arg)
  {
    pthread_detach(pthread_self());
    ThreadPool<T>* tp = (ThreadPool<T>*)arg;
    while(1)
    {
      pthread_mutex_lock(&tp->_mtx);
      while(tp->isEmpty())
      {
        pthread_cond_wait(&tp->_cond,&tp->_mtx);
      }
      //有任务 & 被唤醒了
      T task;
      tp->pop(&task);

      //先解锁再处理任务
      pthread_mutex_unlock(&tp->_mtx);
      task.Run();
    }
  }
  bool isEmpty()
  {
    return task_queue.empty();
  }
  void InitThreadPool()
  {
    pthread_t tid;
    for(int i = 0 ; i < _cap;i++)
    {
      pthread_create(&tid,nullptr,Routine,(void*)this);
    }
  }
  void push(const T& task)
  {
    pthread_mutex_lock(&_mtx);
    task_queue.push(task);
    pthread_mutex_unlock(&_mtx); 
    pthread_cond_signal(&_cond);
  }
  void pop(T* task)
  {
    //由于是在加锁的上下文调用这个接口,所以可以直接拿任务
    *task = task_queue.front();
    task_queue.pop();
  }
private:
  static ThreadPool<T>* ins;
  queue<T> task_queue;
  int _cap;
  pthread_mutex_t _mtx;
  pthread_cond_t _cond; //当没有任务的时候,线程池中的线程需要在条件变量下进行等待
};

template<class T>
ThreadPool<T>* ThreadPool<T>::ins = nullptr;
